package tt.dz.egobus.servicemanager.service.impl;

import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import redis.clients.jedis.Jedis;
import tt.dz.egobus.cache.service.ExtendCacheService;
import tt.dz.egobus.cache.service.impl.ExtendsRedisServiceImpl;
import tt.dz.egobus.servicemanager.core.lock.AbstractRedisCacheLock;
import tt.dz.egobus.servicemanager.core.task.DynamicTask;
import tt.dz.egobus.servicemanager.core.task.DynamicTaskNamespace;
import tt.dz.egobus.servicemanager.service.DynamicTaskService;

import java.util.*;

/**
 * @author Anson
 * @date 17-8-4
 * @name 根据redis获取当前存活的动态任务, 底层采用map形式处理
 * @since 1.0.6
 */
@Service("redisDynamicTaskMapService")
public class RedisDynamicTaskMapService extends ExtendsRedisServiceImpl implements DynamicTaskService {

    private static final String REDIS_DYNAMIC_TASK_CACHE_KEY = "EGOBUS_DYNAMIC_TASK_MAP_CACHE_KEY";
    private static final String REDIS_DYNAMIC_TASK_CACHE_LOCK_KEY = "EGOBUS_DYNAMIC_TASK_MAP_CACHE_LOCK_KEY";

    /**
     * @author Anson
     * @date 17-8-7
     * @name 当前redis缓存锁
     * @since 1.0.6
     */
    protected class RedisDynamicTaskServiceLock extends AbstractRedisCacheLock {
        @Override
        protected ExtendCacheService cacheService() {
            return RedisDynamicTaskMapService.this;
        }

        @Override
        protected String getLockKey() {
            return REDIS_DYNAMIC_TASK_CACHE_LOCK_KEY;
        }
    }

    @Override
    public List<DynamicTask> getCurLiveDynamicTask() {
        Jedis jedis = this.getJedis();
        try {
            Map<String, DynamicTask> taskMap = this.getRedisDynamicTaskCacheMap(jedis);
            if (taskMap == null) {
                return Collections.emptyList();
            }
            List<DynamicTask> list = new ArrayList<DynamicTask>(taskMap.size());
            list.addAll(taskMap.values());
            return list;
        } finally {
            jedis.close();
        }
    }

    @Override
    public void addDynamicTask(DynamicTask... tasks) {
        if (tasks == null || tasks.length == 0) {
            return;
        }
        Jedis jedis = this.getJedis();
        RedisDynamicTaskServiceLock cacheLock = new RedisDynamicTaskServiceLock();
        if (cacheLock.aquireLock()) {
            try {
                for (DynamicTask task : tasks) {
                    if (this.isContainerDynamicTaskKey(jedis, task)) {
                        continue;
                    }
                    this.addDynamicTask(jedis, task);
                }
            } finally {
                jedis.close();
                cacheLock.unlock();
            }
        }
    }

    @Override
    public boolean isContainerDynamicTask(DynamicTask task) {
        if (task == null || StringUtils.isBlank(task.key())) {
            return false;
        }
        Jedis jedis = this.getJedis();
        try {
            return this.isContainerDynamicTaskKey(jedis, task);
        } finally {
            jedis.close();
        }
    }

    @Override
    public void deleteDynamicTask(DynamicTask task) {
        if (task == null || StringUtils.isBlank(task.key())) {
            return;
        }
        this.deleteDynamicTaskNamespace(task);
    }

    @Override
    public void deleteDynamicTaskNamespace(DynamicTaskNamespace taskNamespace) {
        Jedis jedis = this.getJedis();
        String key = this.getRedisDynamicTaskCacheKey();

        RedisDynamicTaskServiceLock cacheLock = new RedisDynamicTaskServiceLock();

        if (cacheLock.aquireLock()) {
            try {

                this.deleteRedisTask(jedis, taskNamespace);

            } finally {
                jedis.close();
                cacheLock.unlock();
            }
        }
    }

    @Override
    public Map<String, DynamicTask> getCurLiveDynamicMapTask() {
        Jedis jedis = this.getJedis();
        try {
            return this.getRedisDynamicTaskCacheMap(jedis);
        } finally {
            jedis.close();
        }
    }


    @Override
    public void modifyDynamicTask(DynamicTask task) {
        if (task == null) {
            return;
        }
        Jedis jedis = this.getJedis();
        String bKey = this.getRedisDynamicTaskCacheKey();
        RedisDynamicTaskServiceLock cacheLock = new RedisDynamicTaskServiceLock();
        if (cacheLock.aquireLock()) {
            try {
                this.modefyRedisTask(jedis, task);
            } finally {
                jedis.close();
                cacheLock.unlock();
            }
        }
    }

    public String getRedisDynamicTaskCacheKey() {
        return REDIS_DYNAMIC_TASK_CACHE_KEY;
    }

    protected boolean isContainerDynamicTaskKey(final Jedis jedis, DynamicTask task) {
        if (task == null || StringUtils.isBlank(task.key())) {
            return false;
        }
        return !StringUtils.isBlank(this.getRedisDynamicTaskJsonSingle(jedis, task.key()));
    }

    /**
     * @param jedis 当前jedis
     * @author Anson
     * @date 17-8-4
     * @name 获取当前缓存
     * 调用者释放当前redis链接
     * @since 1.0.6
     */
    protected Map<String, DynamicTask> getRedisDynamicTaskCacheMap(final Jedis jedis) {
        Map<String, String> hash = this.getRedisDynamicTaskCacheStrMap(jedis);
        Map<String, DynamicTask> map = new HashMap<>();
        if (hash == null || hash.isEmpty()) {
            return map;
        }
        Iterator<Map.Entry<String, String>> iterator = hash.entrySet().iterator();
        Map.Entry<String, String> entry = null;
        String key = "";
        String value = "";
        DynamicTask task = null;
        while (iterator.hasNext()) {
            entry = iterator.next();
            key = entry.getKey();
            value = entry.getValue();
            try {
                task = DynamicTask.jsonStrConvertTask(value);
            } catch (Exception e) {
            }
            if (task == null) {
                continue;
            }
            map.putIfAbsent(key, task);
        }
        return map;
    }


    /**
     * @param jedis 当前jedis
     * @author Anson
     * @date 17-8-4
     * @name 获取当前缓存
     * 调用者释放当前redis链接
     * @since 1.0.6
     */
    protected Map<String, String> getRedisDynamicTaskCacheStrMap(final Jedis jedis) {
        Map<String, String> hash = jedis.hgetAll(this.getRedisDynamicTaskCacheKey());
        return hash;
    }

    /**
     * @param jedis
     * @param key
     * @author Anson
     * @date 17-8-16
     * @name 查询当前某一个任务json
     * 调用者释放当前redis链接
     * @since 1.0.6
     */
    protected String getRedisDynamicTaskJsonSingle(final Jedis jedis, final String key) {
        return jedis.hget(key, key);
    }

    /**
     * @param jedis
     * @param key
     * @author Anson
     * @date 17-8-16
     * @name 查询当前某一个任务
     * 调用者释放当前redis链接
     * @since 1.0.6
     */
    protected DynamicTask getRedisDynamicTaskSingle(final Jedis jedis, final String key) {
        String json = this.getRedisDynamicTaskJsonSingle(jedis, key);
        DynamicTask task = null;
        try {
            task = DynamicTask.jsonStrConvertTask(json);
        } catch (Exception e) {
        }
        return task;
    }

    /**
     * @param jedis
     * @param task
     * @author Anson
     * @date 17-8-16
     * @name 添加当前某一个任务
     * 调用者释放当前redis链接
     * @since 1.0.6
     */
    protected long addDynamicTask(final Jedis jedis, final DynamicTask task) {
        String key = this.getRedisDynamicTaskCacheKey();
        return jedis.hset(key, task.key(), task.toJsonStr());
    }

    /**
     * @param jedis
     * @param task
     * @author Anson
     * @date 17-8-16
     * @name 修改当前某一个任务
     * 调用者释放当前redis链接
     * @since 1.0.6
     */
    protected long modefyRedisTask(final Jedis jedis, final DynamicTask task) {
        String key = this.getRedisDynamicTaskCacheKey();
        return jedis.hset(key, task.key(), task.toJsonStr());
    }

    /**
     * @param jedis
     * @param taskNamespace
     * @author Anson
     * @date 17-8-16
     * @name 删除当前某一个任务
     * 调用者释放当前redis链接
     * @since 1.0.6
     */
    protected long deleteRedisTask(final Jedis jedis, final DynamicTaskNamespace taskNamespace) {
        String key = this.getRedisDynamicTaskCacheKey();
        return jedis.hdel(key, taskNamespace.key());
    }
}
